module ysyx_050369_id(
    input               clk,
    input               rst,
    
    //from  ctrl
    input               id_ready,
    input               id_valid,
    input               i_ex_fence_i,
    //form ex
    //form if
    input               if2id_valid,
    output              id2ex_valid,
    input       [31:0]  i_pc,
    input       [31:0]  i_inst,
    input       [31:0]  i_pre_pc,
    input               i_pre_jump,
    output      [31:0]  o_pre_pc,
    output              o_pre_jump,

    output   [31:0]     o_pc,
    output   [31:0]     o_inst,
    // output   [6 :0]     o_op,
    output   [4 :0]     o_rs1,
    output   [4 :0]     o_rs2,
    output   [4 :0]     o_rd,
    // output    [2:0]     o_ExtOP,//选择立即数产生器的输出类型
    output              o_RegWr,//控制是否对寄存器rd进行写回，为1时写回寄存器
    output              o_ALUAsrc,//选择ALU输入端A的来源。为0时选择rs1，为1时选择PC。
    output    [2:0]     o_ALUBsrc,//选择ALU输入端B的来源。为00时选择rs2，为01时选择imm(当是立即数移位指令时，只有低5位有效)，为10时选择常数4
    output    [5:0]     o_ALUctr , //选择ALU执行的操作，
    output    [2:0]     o_Branch ,//说明分支和跳转的种类，用于生成最终的分支控制信号，
    output              o_MemtoReg ,//选择寄存器rd写回数据来源，为0时选择ALU输出，为1时选择数据存储器输出。
    output              o_MemWr ,//控制是否对数据存储器进行写入，为1时写回存储器
    // output    [2:0]     o_MemOP,  //制数据存储器读写格式，为011时为8字节读写，为010时为4字节读写，为001时为2字节读写带符号扩展，为000时为1字节读写带符号扩展，为110时为2字节读写无符号扩展，为101时为2字节读写无符号扩展，为100时为1字节读写无符号扩展。
    output    [63:0]    o_imm,
    output    [7:0]     o_rmask,
    output    [7:0]     o_wmask,
    output              o_csr_wen

);
    assign id2ex_valid = id_valid;
    reg [31:0]    inst,pc;
    reg [31:0]    pre_pc;
    reg           pre_jump;
    wire   [2:0]  ExtOP;
    always @(posedge clk) begin
        if (rst || i_ex_fence_i || ~if2id_valid) begin
            inst <= 32'b0;
            pc   <= 32'b0;
            pre_pc <= 'b0;
            pre_jump <= 'b0;
        end
        else begin
            if (id_ready ) begin
                inst     <= i_inst    ;
                pc       <= i_pc      ;
                pre_pc   <= i_pre_pc  ;
                pre_jump <= i_pre_jump;
            end
        end
    end 
    assign o_pre_pc    = pre_pc;
    assign o_pre_jump  = pre_jump;
    assign o_pc        = pc;
    assign o_inst      = inst;
    ysyx_050369_decoder ysyx_050369_decoder(
        .inst       (inst),
        .rs1        (o_rs1),
        .rs2        (o_rs2),
        .rd         (o_rd),
        .ExtOP      (ExtOP),
        .RegWr      (o_RegWr),
        .ALUAsrc    (o_ALUAsrc),
        .ALUBsrc    (o_ALUBsrc),
        .ALUctr     (o_ALUctr),
        .Branch     (o_Branch),
        .MemtoReg   (o_MemtoReg),
        .MemWr      (o_MemWr),
        .wmask      (o_wmask),
        .rmask      (o_rmask),
        .csr_wen    (o_csr_wen)
    );
    ysyx_050369_imm   res_imm(
        .ExtOP  (ExtOP),
        .inst   (inst),
        .imm    (o_imm)
    );

endmodule
module ysyx_050369_decoder(
    input       [31:0]  inst,
    output      [4:0]   rs1,
    output      [4:0]   rs2,
    output      [4:0]   rd,
    output      [2:0]   ExtOP,
    output              RegWr,
    output              ALUAsrc,
    output      [2:0]   ALUBsrc,
    output      [5:0]   ALUctr,
    output      [2:0]   Branch,
    output              MemtoReg,
    output              MemWr,
    output      [7:0]   rmask,
    output      [7:0]   wmask,
    output              csr_wen
);

wire [3:0] mask_flag;
wire r_type   ;
wire rw_type  ;
wire iw_type  ;
wire i_type   ;
wire s_type   ;
wire l_type   ;
wire jal_type ;
wire jalr_type;
wire b_type   ;
wire auipc    ;
wire lui      ;
wire m_type   ;
wire mw_type  ;
wire csr_type ;
wire [5:0]  i_ALUctr;
wire [5:0]  r_ALUctr;
wire [5:0]  m_ALUctr;
wire [5:0]  csr_ALUctr;
wire  [2 :0]  func3;
wire  [6 :0]  func7;
wire  [6 :0]  op_code;
assign r_type   = (op_code  == `ysyx_050369_TYPE_R_M &&~func7[0])?1'b1:1'b0;
assign rw_type  = (op_code  == `ysyx_050369_TYPE_R_MW&&~func7[0])?1'b1:1'b0;
assign m_type   = (op_code  == `ysyx_050369_TYPE_R_M && func7[0])?1'b1:1'b0;
assign mw_type  = (op_code  == `ysyx_050369_TYPE_R_MW&& func7[0])?1'b1:1'b0;
assign iw_type  = (op_code  == `ysyx_050369_TYPE_IW  )?1'b1:1'b0;
assign i_type   = (op_code  == `ysyx_050369_TYPE_I   )?1'b1:1'b0;
assign s_type   = (op_code  == `ysyx_050369_TYPE_S   )?1'b1:1'b0;
assign l_type   = (op_code  == `ysyx_050369_TYPE_L   )?1'b1:1'b0;
assign jal_type = (op_code  == `ysyx_050369_JAL      )?1'b1:1'b0;
assign jalr_type= (op_code  == `ysyx_050369_JALR     )?1'b1:1'b0;
assign b_type   = (op_code  == `ysyx_050369_TYPE_B   )?1'b1:1'b0;
assign auipc    = (op_code  == `ysyx_050369_AUIPC    )?1'b1:1'b0;
assign lui      = (op_code  == `ysyx_050369_LUI      )?1'b1:1'b0;
assign csr_type = (op_code  == `ysyx_050369_TYPE_CSR && func3 != 0)?1'b1:1'b0; 

assign  op_code= inst[6:0];
assign  func3  = inst[14:12];
assign  func7  = inst[31:25];

assign  rs1    = (jal_type || lui || auipc)? 'b0 : inst[19:15];
assign  rs2    = (r_type || rw_type || m_type || mw_type || s_type || b_type )?inst[24:20]:'b0 ;
assign  rd     = (b_type || s_type ) ?5'b0: inst[11:7];

assign RegWr    =~(b_type   || s_type    || op_code == 0);
assign ALUAsrc  =  jal_type || jalr_type || auipc;
assign MemtoReg =  l_type;
assign rmask    =  l_type?{func3[2],3'b0,mask_flag}:8'b0;
assign MemWr    =  s_type;
assign wmask    =  s_type?{4'b0,mask_flag}:8'b0;

assign csr_wen  = (csr_type && (func3[1:0]==2'b01 || (func3[1] == 1 && rs1 != 0)))?1'b1:1'b0;

assign ExtOP    =   (i_type || iw_type || l_type || jalr_type || csr_type) ? `ysyx_050369_imm_I :
                    (r_type || rw_type || m_type || mw_type )   ? `ysyx_050369_imm_R :
                    s_type                                      ? `ysyx_050369_imm_S :
                    b_type                                      ? `ysyx_050369_imm_B :
                    jal_type                                    ? `ysyx_050369_imm_J :
                    (lui || auipc)                              ? `ysyx_050369_imm_U : 'b0;

assign Branch   =   jal_type ?  3'b001 :
                    jalr_type?  3'b010 :
                    b_type   ?  {1'b1,func3[2],func3[0]} : 'b0;

assign ALUBsrc  =   (i_type || iw_type || l_type || s_type || lui || auipc ) ? 3'b001:
                    (jal_type || jalr_type )                                 ? 3'b010:
                     csr_type                                                ? {~func3[2],func3[2],1'b1} : 'b0;

assign i_ALUctr =   (~func3[2] &&func3[1]             )?{func3[0],2'b10,func3[2:1],1'b0} :
                    ( func3[2] &&func3[0] && ~func3[1])?{1'b0    ,func7[5],1'b0,func3} :
                    {3'b0,func3};
assign r_ALUctr =   i_ALUctr | {1'b0,~(|func3)&&func7[5],4'b0};
assign m_ALUctr =   {1'b0,func3[2]&&~func3[0],1'b1,func3[2:1],func3[0]&&~func3[2]};
assign csr_ALUctr=  {func3[0]&&func3[1],2'b0,func3[1],1'b1,func3[0]};
assign ALUctr   =   i_type    ? i_ALUctr              :
                    iw_type   ? {1'b1,i_ALUctr[4:0]}  :
                    r_type    ? r_ALUctr              :
                    m_type    ? m_ALUctr              :
                    rw_type   ? {1'b1,r_ALUctr[4:0]}  : 
                    mw_type   ? {1'b1,m_ALUctr[4:0]}  :
                    csr_type  ? csr_ALUctr            :
                     b_type   ? {func3[1],1'b1,2'b0,func3[2],1'b0} :
                     lui      ? 6'b000011 : 'b0 ;
                    

assign  mask_flag = (func3[1:0] == 2'b00)? 4'h1:
                    (func3[1:0] == 2'b01)? 4'h3:
                    (func3[1:0] == 2'b10)? 4'h7:
                    (func3[1:0] == 2'b11)? 4'hf:'b0;

endmodule
module ysyx_050369_imm(
    input  [2:0]    ExtOP,
    input  [31:0]   inst,
    output [63:0]   imm
);


wire [31:0]imm_I,imm_B,imm_U,imm_J,imm_S;
assign imm_I={{20{inst[31]}},inst[31:20]};
assign imm_U={              inst[31:12],12'b0};
assign imm_S={{20{inst[31]}},inst[31:25],inst[11:7]};
assign imm_J={{12{inst[31]}},inst[19:12], inst[20], inst[30:21], 1'b0};
assign imm_B={{20{inst[31]}},inst[7],inst[30:25],inst[11:8],1'b0};
assign imm[31:0]=(ExtOP == `ysyx_050369_imm_I) ? imm_I :
                (ExtOP == `ysyx_050369_imm_U) ? imm_U :
                (ExtOP == `ysyx_050369_imm_S) ? imm_S :
                (ExtOP == `ysyx_050369_imm_B) ? imm_B :
                (ExtOP == `ysyx_050369_imm_J) ? imm_J :32'b0;
assign imm[63:32] = {32{inst[31]}};
endmodule